﻿using Xenta.Entities;
using Xenta.Operations;
using Xenta.Security;

namespace Xenta.Utils
{
    /// <summary>
    /// Contains extension methods.
    /// </summary>
    public static partial class Extensions
    {
        #region IWorkingContext

        /// <summary>
        /// Gets the session entity associated withe the context.
        /// </summary>
        /// <param name="ctx">The context.</param>
        /// <param name="uow">The unit of work.</param>
        /// <returns>The entity, if it exists; otherwise null.</returns>
        public static SessionEntity Session(this IWorkingContext ctx, IUnitOfWork uow)
        {
            return uow.Execute(new GetSessionByGuid
            {
                Guid = ctx.SID
            }).Result;
        }

        /// <summary>
        /// Gets the account entity associated withe the context.
        /// </summary>
        /// <param name="ctx">The context.</param>
        /// <param name="uow">The unit of work.</param>
        /// <returns>The entity or null.</returns>
        public static AccountEntity Account(this IWorkingContext ctx, IUnitOfWork uow)
        {
            var session = Session(ctx, uow);
            if(session == null)
                return null;
            return session.Account;
        }

        /// <summary>
        /// Gets the file owner entity associated withe the context.
        /// </summary>
        /// <param name="ctx">The context.</param>
        /// <param name="uow">The unit of work.</param>
        /// <returns>The entity or null.</returns>
        public static FileOwnerEntity FileOwner(this IWorkingContext ctx, IUnitOfWork uow)
        {
            var account = Account(ctx, uow);
            if(account == null)
                return null;
            return uow.Execute(new GetFileOwnerByAccount
            {
                AccountID = account.EntityID
            }).Result;
        }

        #endregion

        #region SecurityPolicy

        /// <summary>
        /// Adds the security rule to a security policy.
        /// </summary>
        /// <param name="policy">The security policy.</param>
        /// <returns>The security policy.</returns>
        public static SecurityPolicy IsAuthenticated(this SecurityPolicy policy)
        {
            policy.Add(new IsAuthenticatedSecurityRule());
            return policy;
        }

        /// <summary>
        /// Adds the security rule to a security policy.
        /// </summary>
        /// <param name="policy">The security policy.</param>
        /// <returns>The security policy.</returns>
        public static SecurityPolicy IsVerified(this SecurityPolicy policy)
        {
            policy.Add(new IsVerifiedSecurityRule());
            return policy;
        }

        /// <summary>
        /// Adds the security rule to a security policy.
        /// </summary>
        /// <param name="policy">The security policy.</param>
        /// <param name="roleCode">The role codes.</param>
        /// <returns>The security policy.</returns>
        public static SecurityPolicy InRole(this SecurityPolicy policy, string roleCode)
        {
            return InAllRoles(policy, roleCode);
        }

        /// <summary>
        /// Adds the security rule to a security policy.
        /// </summary>
        /// <param name="policy">The security policy.</param>
        /// <param name="roleCodes">The role codes.</param>
        /// <returns>The security policy.</returns>
        public static SecurityPolicy InAnyRole(this SecurityPolicy policy, params string[] roleCodes)
        {
            if(roleCodes != null && roleCodes.Length != 0)
                policy.Add(new InAnyRoleSecurityRule(roleCodes));
            return policy;
        }

        /// <summary>
        /// Adds the security rule to a security policy.
        /// </summary>
        /// <param name="policy">The security policy.</param>
        /// <param name="roleCodes">The role codes.</param>
        /// <returns>The security policy.</returns>
        public static SecurityPolicy InAllRoles(this SecurityPolicy policy, params string[] roleCodes)
        {
            if(roleCodes != null && roleCodes.Length != 0)
                policy.Add(new InAllRolesSecurityRule(roleCodes));
            return policy;
        }

        /// <summary>
        /// Adds the security rule to a security policy.
        /// </summary>
        /// <param name="policy">The security policy.</param>
        /// <param name="permissionCode">The permission code.</param>
        /// <returns>The security policy.</returns>
        public static SecurityPolicy HasPermission(this SecurityPolicy policy, string permissionCode)
        {
            return HasAllPermissions(policy, permissionCode);
        }

        /// <summary>
        /// Adds the security rule to a security policy.
        /// </summary>
        /// <param name="policy">The security policy.</param>
        /// <param name="permissionCodes">The permission codes.</param>
        /// <returns>The security policy.</returns>
        public static SecurityPolicy HasAnyPermission(this SecurityPolicy policy, params string[] permissionCodes)
        {
            if(permissionCodes != null && permissionCodes.Length != 0)
                policy.Add(new HasAnyPermissionSecurityRule(permissionCodes));
            return policy;
        }

        /// <summary>
        /// Adds the security rule to a security policy.
        /// </summary>
        /// <param name="policy">The security policy.</param>
        /// <param name="permissionCodes">The permission codes.</param>
        /// <returns>The security policy.</returns>
        public static SecurityPolicy HasAllPermissions(this SecurityPolicy policy, params string[] permissionCodes)
        {
            if(permissionCodes != null && permissionCodes.Length != 0)
                policy.Add(new HasAllPermissionsSecurityRule(permissionCodes));
            return policy;
        }

        #endregion
    }
}
